import type {RouteComponent, RouteRecordRaw} from 'vue-router'
import {toRaw} from "vue";
import HexUtils from "@/utils/HexUtils";
import GlobalConstants from "@/constants/GlobalConstants";


const pathComponentMap = new Map(Object.entries(import.meta.glob('@/pages/**/*.{vue,tsx}')))
const getComponent = (path: string | RouteComponent): RouteComponent => {
  if (typeof path !== 'string') {
    // 如果传入的不是字符串，直接返回
    return path
  }
  // 确保路径以 .vue 结尾，如果不是，则添加
  const vuePath = path.endsWith('.vue') ? path : `${path}.vue`
  // 构建完整的视图路径
  const fullPath = vuePath.startsWith('/') ? `${GlobalConstants.PAGE_DIR}${vuePath}` : `${GlobalConstants.PAGE_DIR}/${vuePath}`
  // 尝试从 map 中获取组件
  const component = pathComponentMap.get(fullPath)
  // 如果找到了组件，返回它；否则返回 404 页面组件
  return component ?? (pathComponentMap.get('/src/pages/error/404.vue') as RouteComponent)
}

export class MenuUtils {
  private static idCounter = 1

  /**
   * 取消树形节点之间的关联关系，用于序列化
   * @param menus
   */
  public static disconnectTreeNodeRelations<T extends MenuRecordRaw>(menus: Array<T>): Array<T> {
    //深克隆，避免影响原始数据，需要先将代理对象转换为普通对象
    menus = structuredClone(toRaw(menus))
    for (const menu of menus) {
      menu.parent = undefined
      if (menu.menuType !== 'link') {
        menu.children = MenuUtils.disconnectTreeNodeRelations(menu.children || []);
      }
    }
    return menus
  }

  /**
   * 菜单排序
   * @param menus
   */
  public static sort<T extends MenuRecordRaw>(menus: Array<T>) {
    return menus.sort((child1, child2) => (child1.sort as number) - (child2.sort as number))
  }

  /**
   * 处理ID
   * @param menus
   */
  public static processId<T extends MenuRecordRaw>(menus: Array<T> = []) {
    if (Array.isArray(menus)) {
      menus.forEach(menu => {
        menu.id = menu.id || `${this.idCounter++}`;
        if (menu.menuType !== 'link') {
          this.processId(menu.children || [])
        }
      })
    }
    return menus;
  }

  /**
   * 被处理后的菜单列表，已经关联父级，返回值为原菜单列表，可能没有去重，如果要去重可以使用[...menuMap.values()]
   * @param menus 需要处理的菜单列表
   * @param menuMap 菜单ID和菜单的映射
   * @param routerSet 路由列表
   * @param keepAliveNameSet 需要缓存的路由名字
   */
  public static processList<T extends MenuRecordRaw>(
    menus: Array<T> = [],
    menuMap?: Map<string, T>,
    routerSet?: Set<RouteRecordRaw>,
    keepAliveNameSet?: Set<string>
  ): Array<T> {
    if (!Array.isArray(menus)) {
      return []
    }
    return MenuUtils.sort(
      menus.map((menu) => this._process(menu, undefined, menuMap, routerSet, keepAliveNameSet))
    )
  }

  /**
   * 返回菜单，已经关联父级的菜单，返回值为原菜单
   * @param menuItem 被处理的节点
   * @param parent 父节点
   * @param menuMap 菜单ID和菜单的映射
   * @param routerSet 路由列表
   * @param keepAliveNameSet 需要缓存的路由名字
   */
  private static _process<T extends MenuRecordRaw>(
    menuItem: T,
    parent?: MenuRecordRaw,
    menuMap?: Map<string, T>,
    routerSet?: Set<RouteRecordRaw>,
    keepAliveNameSet?: Set<string>
  ): T {
    const id = menuItem.id || `${this.idCounter++}`
    menuItem.id = id
    menuItem.hidden = menuItem.hidden === true
    menuItem.disabled = menuItem.disabled === true
    menuItem.sort = menuItem.sort === undefined ? Number(id) : menuItem.sort
    menuItem.parent = parent
    if (parent?.level) {
      menuItem.level = parent.level + 1;
    } else {
      menuItem.level = 1;
    }
    if (menuItem.menuType !== 'link') {
      menuItem.children = MenuUtils.sort(menuItem.children?.map((child) => this._process(child, menuItem, menuMap, routerSet, keepAliveNameSet)) || [])
    }
    const menuType = menuItem.menuType;
    if (menuType === 'dir') {
      //dir不需要配置path，所以设置默认path
      menuItem.path = menuItem.path || `/${menuItem.id}`
    } else if (menuType === 'router') {
      const routeItem: RouteItem = menuItem as RouteItem;
      if ((parent === undefined || parent.menuType === 'dir') && (!routeItem.disabled) && (!routeItem.hidden)) {
        if (routeItem.path.includes("*") || routeItem.path.includes(":")) {
          throw new Error(`会被展示在菜单树上的路由不支持动态路径：${menuItem.path}`);
        }
      }
      if (!routeItem.path.startsWith("/")) {
        if (routeItem.isTopPage) {
          throw new Error("顶层路由的路径必须以/开头");
        } else {
          console.warn("建议非顶层路由的路径以/开头，否则访问时需要拼接/layout前缀");
        }
      }
      routeItem.isTopPage = routeItem.isTopPage === true;
      routeItem.keepAlive = routeItem.keepAlive === true;
      routeItem.isAffix = routeItem.isAffix === true;
      if (parent && parent.menuType !== 'dir') {
        //如果父级菜单存在，并且不是一个目录，强制隐藏当前菜单，其实此行代码删除也不会影响结果，因为菜单树组件没有对路由类型菜单的children进行遍历
        //此处设置为true，为了方便其他地方使用当前路由的hidden属性时，与左侧菜单树表现一致，避免菜单树不显示，但是打印出hidden为true的情况
        routeItem.hidden = true
      }
      //父级菜单被禁用，将导致子级菜单均被禁用
      routeItem.disabled = parent?.disabled || menuItem.disabled
      //父级菜单被隐藏，将导致子级菜单均被隐藏
      routeItem.hidden = parent?.hidden || menuItem.hidden
      if (parent != undefined && parent.menuType !== 'dir') {
        routeItem.isAffix = false
      }
      const route: RouteRecordRaw = {
        path: menuItem.path,
        //名字不存在时，支持使用id进行路由跳转
        name: routeItem.name || `${id}`,
        component: getComponent(routeItem.component),
        meta: {
          id: id,
          title: routeItem.title,
          menuType:routeItem.menuType,
          isTopPage: routeItem.isTopPage,
          isAffix: routeItem.isAffix,
          //父级菜单被禁用，将导致子级菜单均被禁用
          disabled: routeItem.disabled,
          hidden: routeItem.hidden,
          path: routeItem.path,
          parentMenuType: parent?.menuType,
          icon: routeItem.icon,
          menu: routeItem
        }
      };
      if (routeItem.keepAlive && routeItem.componentName) {
        keepAliveNameSet?.add(routeItem.componentName)
      }
      if (!routeItem.disabled) {
        routerSet?.add(route);
      }
    } else if (menuType === 'iframe') {
      const iframeItem: IframeItem = menuItem as IframeItem;
      if (!iframeItem.oriURL?.length) {
        throw new Error('oriURL不能为空')
      }
      iframeItem.path = `/iframe/${HexUtils.strToHex(iframeItem.oriURL)}`
      iframeItem.isAffix = iframeItem.isAffix === true;
      //父级菜单被禁用，将导致子级菜单均被禁用
      iframeItem.disabled = parent?.disabled || menuItem.disabled
      if (parent != undefined && parent.menuType !== 'dir') {
        iframeItem.isAffix = false
      }
      //父级菜单被隐藏，将导致子级菜单均被隐藏
      iframeItem.hidden = parent?.hidden || menuItem.hidden;
      const route: RouteRecordRaw = {
        path: iframeItem.path,
        name: `${id}`,
        component: () => import('@/pages/system/IframePage.vue'),
        meta: {
          id: id,
          title: iframeItem.title,
          menuType:iframeItem.menuType,
          isTopPage: false,
          isAffix: iframeItem.isAffix,
          //父级菜单被禁用，将导致子级菜单均被禁用
          disabled: iframeItem.disabled,
          hidden: iframeItem.hidden,
          path: iframeItem.path,
          parentMenuType: parent?.menuType,
          icon: iframeItem.icon,
          menu: iframeItem
        }
      };
      if (!iframeItem.disabled) {
        routerSet?.add(route);
      }
    } else if (menuType === 'link') {
      const linkItem: LinkItem = menuItem as LinkItem;
      if (!linkItem.oriURL?.length) {
        throw new Error('oriURL不能为空')
      }
      linkItem.path = `/link/${HexUtils.strToHex(linkItem.oriURL)}`
    }
    menuMap?.set(id, menuItem)
    return menuItem
  }

}
